<?php
declare(ENCODING = 'utf-8');

/*
 * CR_Value.php created on 14 avr. 08 
 * Author: Rodrigue Le Gall
 * 
 * This file is inspired by the project Typo3
 *
 * RPortal is an open source web based Content Management System
 * Copyright (C) 2002-2008  Rodrigue Le Gall
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

/**
 * A Value
 *
 * @package CR
 */
class CR_Value implements phpCR_ValueInterface {

	/**
	 * @var mixed
	 */
	protected $value;

	/**
	 * @var integer
	 */
	protected $type;

	/**
	 * @var $nonStreamConversionAllowed
	 */
	protected $nonStreamConversionAllowed = TRUE;

	/**
	 * @var $streamConversionAllowed
	 */
	protected $streamConversionAllowed = TRUE;

	/**
	 * Constructs a Value object from the given $value and $type arguments
	 *
	 * @param mixed $value The value of the Value object
	 * @param integer $type A type, see constants in phpCR_PropertyType
	 * @return void
	 */
	public function __construct($value, $type = phpCR_PropertyType::UNDEFINED) {
		$this->value = $value;
		$this->type = $type;
	}

	/**
	 * Returns a string representation of this value.
	 *
	 * @return string A String representation of the value of this property.
	 * @throws phpCR_ValueFormatException if conversion to a String is not possible.
	 * @throws phpCR_IllegalStateException if getStream has previously been called on this Value instance.
	 * @throws phpCR_RepositoryException if another error occurs.
	 */
	public function getString() {
		if (!$this->nonStreamConversionAllowed) {
			throw new BadMethodCallException('getStream() has previously been called on this Value object.', 1190032940);
		}
		$this->streamConversionAllowed = FALSE;

		switch ($this->type) {
			case phpCR_PropertyType::DATE:
				return date_format(new DateTime($this->value), DATE_ISO8601);
				break;
			default:
				return (string)$this->value;
		}
	}

	/**
	 * Returns the value as string, alias for getString()
	 *
	 * @return string
	 */
	public function __toString() {
		return $this->getString();
	}

	/**
	 * Returns an InputStream representation of this value. Uses the standard
	 * conversion to binary (see JCR specification).
	 * It is the responsibility of the caller to close the returned InputStream.
	 *
	 * @return InputStream An InputStream representation of this value.
	 * @throws BadMethodCallException if a non-stream get method has previously been called on this Value instance.
	 * @throws phpCR_RepositoryException if another error occurs.
	 * @todo Implement this. We may need the resource manager first...
	 */
	public function getStream() {
		if (!$this->streamConversionAllowed) {
			throw new BadMethodCallException('A non stream get method has previously been called on this Value object.', 1190032941);
		}
		$this->nonStreamConversionAllowed = FALSE;

		throw new phpCR_RepositoryException('getStream() has not yet been implemented.', 1190034714);
	}

	/**
	 * Returns a long representation of this value.
	 *
	 * @return string A long representation of the value of this property.
	 * @throws phpCR_ValueFormatException if conversion to a long is not possible.
	 * @throws BadMethodCallException if getStream has previously been called on this Value instance.
	 * @throws phpCR_RepositoryException if another error occurs.
	 */
	public function getLong() {
		if (!$this->nonStreamConversionAllowed) {
			throw new BadMethodCallException('getStream() has previously been called on this Value object.', 1190032942);
		}
		$this->streamConversionAllowed = FALSE;
		return (double)$this->value;
	}

	/**
	 * Returns a double representation of this value. Is an alias for getLong().
	 *
	 * @return string A double representation of the value of this property.
	 * @throws phpCR_ValueFormatException if conversion to a double is not possible.
	 * @throws BadMethodCallException if getStream has previously been called on this Value instance.
	 * @throws phpCR_RepositoryException if another error occurs.
	 */
	public function getDouble() {
		return $this->getLong();
	}

	/**
	 * Returns a DateTime representation of this value.
	 *
	 * @return DateTime A DateTime representation of the value of this property.
	 * @throws phpCR_ValueFormatException if conversion to a DateTime is not possible.
	 * @throws BadMethodCallException if getStream has previously been called on this Value instance.
	 * @throws phpCR_RepositoryException if another error occurs.
	 */
	public function getDate() {
		if (!$this->nonStreamConversionAllowed) {
			throw new BadMethodCallException('getStream() has previously been called on this Value object.', 1190032944);
		}
		$this->streamConversionAllowed = FALSE;

		try {
			$DateTime = new DateTime($this->value);
		} catch (Exception $e) {
			throw new phpCR_ValueFormatException('Conversion to a DateTime object is not possible. Cause: ' . $e->getMessage(), 1190034628);
		}
		return $DateTime;
	}

	/**
	 * Returns a boolean representation of this value.
	 *
	 * @return string A boolean representation of the value of this property.
	 * @throws phpCR_ValueFormatException if conversion to a boolean is not possible.
	 * @throws BadMethodCallException if getStream has previously been called on this Value instance.
	 * @throws phpCR_RepositoryException if another error occurs.
	 */
	public function getBoolean() {
		if (!$this->nonStreamConversionAllowed) {
			throw new BadMethodCallException('getStream() has previously been called on this Value object.', 1190032945);
		}
		$this->streamConversionAllowed = FALSE;
		return (boolean)$this->value;
	}

	/**
	 * Returns the type of this Value. One of:
	 * * phpCR_PropertyType::STRING
	 * * phpCR_PropertyType::DATE
	 * * phpCR_PropertyType::BINARY
	 * * phpCR_PropertyType::DOUBLE
	 * * phpCR_PropertyType::LONG
	 * * phpCR_PropertyType::BOOLEAN
	 * * phpCR_PropertyType::NAME
	 * * phpCR_PropertyType::PATH
	 * * phpCR_PropertyType::REFERENCE
	 * * phpCR_PropertyType::WEAKREFERENCE
	 * * phpCR_PropertyType::URI
	 *
	 * The type returned is that which was set at property creation.
	 * @return integer The type of the value
	 */
	public function getType() {
		return $this->type;
	}

}
